/*
* Copyright 2008-2010 Hippo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onehippo.forge.weblogdemo.hstextensions;
import javax.jcr.Node;
import org.hippoecm.hst.configuration.hosting.Mount;
import org.hippoecm.hst.content.rewriter.impl.SimpleContentRewriter;
import org.hippoecm.hst.core.linking.HstLink;
import org.hippoecm.hst.core.request.HstRequestContext;
import org.hippoecm.hst.utils.SimpleHtmlExtractor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* ContentRewriterImpl does the same as {@link SimpleContentRewriter}.
* Supports adding rel="external" to external links or rewriting all links to external form, e.g. http://example.com/link.html.
* @author jashaj
*
*/
public class ContentRewriterImpl extends SimpleContentRewriter {
private static final Logger log = LoggerFactory.getLogger(ContentRewriterImpl.class);
private static final String REL_EXTERNAL = " rel=\"external\"";
/**
* @see SimpleContentRewriter#rewrite(String, Node, HstRequestContext)
*/
@Override
public String rewrite(String html, Node node, HstRequestContext requestContext) {
return rewriteContent(html, node, requestContext, false);
}
/**
* Rewrites all links to external form, e.g. http://example.com/link.html. Useful for content exchange through feeds
* @param html String of the HTML
* @param node {@link Node} that contains the HTML
* @param requestContext {@link HstRequestContext}
* @return rewritten String of the HTML with all links rewritten to external form
*/
public String rewriteToExternal(String html, Node node, HstRequestContext requestContext) {
return rewriteContent(html, node, requestContext, true);
}
/**
* Internal method that rewrites all links, optionally makes links in external form or adds a rel="external" to external links
* @param html String of the HTML
* @param node {@link Node} that contains the HTML
* @param requestContext {@link HstRequestContext}
* @param externalizeLinks boolean that defines if all links should be rewritten to external form, e.g. http://example.com/link.html
* @return rewritten String of the HTML
*/
private String rewriteContent(String html, Node node, HstRequestContext requestContext,
boolean externalizeLinks) {
// only create if really needed
StringBuilder sb = null;
// strip off html & body tag
String innerHTML = SimpleHtmlExtractor.getInnerHtml(html, "body", false);
if (innerHTML == null) {
innerHTML = html;
}
innerHTML = innerHTML.trim().replaceAll("facetselect=\".+?\"", "");
int globalOffset = 0;
while (innerHTML.indexOf(LINK_TAG, globalOffset) > -1) {
int offset = innerHTML.indexOf(LINK_TAG, globalOffset);
int hrefIndexStart = innerHTML.indexOf(HREF_ATTR_NAME, offset);
if (hrefIndexStart == -1) {
break;
}
if (sb == null) {
sb = new StringBuilder(html.length());
}
hrefIndexStart += HREF_ATTR_NAME.length();
offset = hrefIndexStart;
int endTag = innerHTML.indexOf(END_TAG, offset);
boolean appended = false;
if (hrefIndexStart < endTag) {
int hrefIndexEnd = innerHTML.indexOf(ATTR_END, hrefIndexStart);
if (hrefIndexEnd > hrefIndexStart) {
String documentPath = innerHTML.substring(hrefIndexStart, hrefIndexEnd);
offset = endTag;
sb.append(innerHTML.substring(globalOffset, hrefIndexStart));
if (isExternal(documentPath)) {
sb.append(documentPath);
} else {
HstLink href = getDocumentLink(documentPath, node, requestContext, (Mount) null);
if (href != null && href.getPath() != null) {
sb.append(href.toUrlForm(requestContext, externalizeLinks));
} else {
log.warn("Skip href because url is null");
}
}
sb.append(innerHTML.substring(hrefIndexEnd, endTag));
if (!externalizeLinks && isExternal(documentPath)) {
sb.append(REL_EXTERNAL);
}
appended = true;
}
}
if (!appended && offset > globalOffset) {
sb.append(innerHTML.substring(globalOffset, offset));
}
globalOffset = offset;
}
if (sb != null) {
sb.append(innerHTML.substring(globalOffset, innerHTML.length()));
innerHTML = String.valueOf(sb);
sb = null;
}
globalOffset = 0;
while (innerHTML.indexOf(IMG_TAG, globalOffset) > -1) {
int offset = innerHTML.indexOf(IMG_TAG, globalOffset);
int srcIndexStart = innerHTML.indexOf(SRC_ATTR_NAME, offset);
if (srcIndexStart == -1) {
break;
}
if (sb == null) {
sb = new StringBuilder(innerHTML.length());
}
srcIndexStart += SRC_ATTR_NAME.length();
offset = srcIndexStart;
int endTag = innerHTML.indexOf(END_TAG, offset);
boolean appended = false;
if (srcIndexStart < endTag) {
int srcIndexEnd = innerHTML.indexOf(ATTR_END, srcIndexStart);
if (srcIndexEnd > srcIndexStart) {
String srcPath = innerHTML.substring(srcIndexStart, srcIndexEnd);
offset = endTag;
sb.append(innerHTML.substring(globalOffset, srcIndexStart));
if (isExternal(srcPath)) {
sb.append(srcPath);
} else {
HstLink binaryLink = getBinaryLink(srcPath, node, requestContext, (Mount) null);
if (binaryLink != null && binaryLink.getPath() != null) {
sb.append(binaryLink.toUrlForm(requestContext, externalizeLinks));
} else {
log.warn("Could not translate image src. Skip src");
}
}
sb.append(innerHTML.substring(srcIndexEnd, endTag));
appended = true;
}
}
if (!appended && offset > globalOffset) {
sb.append(innerHTML.substring(globalOffset, offset));
}
globalOffset = offset;
}
if (sb == null) {
return innerHTML;
} else {
sb.append(innerHTML.substring(globalOffset, innerHTML.length()));
return sb.toString();
}
}
}